
package edu.uoc.tdp.servidor.bbdd.proves;

import edu.uoc.tdp.beans.proves.RondaEliminatoria;
import edu.uoc.tdp.beans.proves.RondaFinal;
import edu.uoc.tdp.bbdd.GestorDiscConnexio;
import edu.uoc.tdp.beans.proves.PreguntaResposta;
import edu.uoc.tdp.beans.proves.Ronda;
import edu.uoc.tdp.common.EOlympicsException;
import edu.uoc.tdp.common.EOlympicsExceptionRonda;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Grup tdp 1x4J
 */
//TODO NOTES XMARTI. 
/* Fet i provat. 
 * - getPreguntesRespostesRonda
 * - getRonda
 * - getRondaEliminatoria
 * - GetRondaFinal
 * - setAltarespostesRonda
 * - setAltaRonda
 * Falta implementar
 * - modificar ronda
 * - dades de l'auditoria. tant de ronda com RespostesCorrectes
 * 
 */
public class GestorRonda {
    private GestorDiscConnexio gestor;
    private Connection connexio;    
    
    /**
     * Constructor generic de GestorRonda
     */
    public GestorRonda(){
        this.gestor=new GestorDiscConnexio();
        this.connexio=gestor.getConnexio();         
    }
    /**
     * Constructor amb un paràmetre. 
     * @param pGestor           Gestor de disc genèric 
     */
    public GestorRonda(GestorDiscConnexio pGestor){
        this.gestor=pGestor;
        connexio=gestor.getConnexio();
    }
    /**
     * Accessor de lectura, obté una ronda eliminatòria.
     * @param idProva               Identificador d'una prova
     * @return  RondaEliminatoria   Una ronda eliminatoria
     * @throws SQLException
     * @throws EOlympicsException 
     */
    
    public RondaEliminatoria getRondaEliminatoria(Integer idProva) throws  EOlympicsException{        
       RondaEliminatoria ronda=null;       
        Statement st=gestor.creaSentencia();
        String sql="SELECT R.nombrePreguntes,R.dataIniciRealitzacio,R.dataFiRealitzacio "
                + "FROM RONDA R "                
                + "WHERE R.idProva="+ idProva 
                + " And R.tipusRonda='E'";
        try{
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                              
                ronda= new RondaEliminatoria(rs.getInt(1),rs.getDate(2),rs.getDate(3),
                                 getPreguntesRespostesRonda(idProva,"E"));
            }
            st.close();
            rs.close();
        }catch (SQLException sqle){
            System.out.println(sqle.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_SQL);
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
        }
        
        return ronda;
    } 
   /* public Ronda getRondaEliminatoria(Integer idProva) throws SQLException, EOlympicsException{        
        return getRonda(idProva,"E");
    }*/
    /**
     * Accessor de lectura, obté una ronda final.
     * @param idProva               identificador d'una prova.
     * @return RondaFinal           Una ronda final.
     * @throws SQLException
     * @throws EOlympicsException 
     */
    
    public RondaFinal getRondaFinal(Integer idProva) throws  EOlympicsException{
       RondaFinal ronda=null;       
        Statement st=gestor.creaSentencia();
        String sql="SELECT R.nombrePreguntes,R.dataIniciRealitzacio,R.dataFiRealitzacio "
                + "FROM RONDA R "                
                + "WHERE R.idProva="+ idProva 
                + " And R.tipusRonda='F'";
        try{
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                              
                ronda= new RondaFinal(rs.getInt(1),rs.getDate(2),rs.getDate(3),
                                 getPreguntesRespostesRonda(idProva,"F"));
            }
            st.close();
            rs.close();
        }catch (SQLException sqle){
            System.out.println(sqle.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_SQL);
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
        }
        
        return ronda;
    }
    
    /**
     * Accessor de lectura que obté una ronda
     * @param idProva               identificador de la prova
     * @param tipus                 identificador de la ronda (E: eliminatoria, F: final)
     * @return ronda                Una ronda
     * @throws SQLException
     * @throws EOlympicsException 
     */
    private Ronda getRonda(Integer idProva, String tipus) throws  EOlympicsException{
        Ronda ronda=null;       
        Statement st=gestor.creaSentencia();
        String sql="SELECT R.nombrePreguntes,R.dataIniciRealitzacio,R.dataFiRealitzacio "
                + "FROM RONDA R "                
                + "WHERE R.idProva="+ idProva 
                + " And R.tipusRonda='"+tipus+"'";
        try{
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                              
                ronda= new Ronda(rs.getInt(1),rs.getDate(2),rs.getDate(3),
                                 getPreguntesRespostesRonda(idProva,tipus));
            }
            st.close();
            rs.close();
        }catch (SQLException sqle){
            System.out.println(sqle.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_SQL);
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
        }
        
        return ronda;
    }
    /**
     * Accessor de lectura que obté les preguntes i respostes d'una ronda
     * @param idProva               Identificador de la prova
     * @param tipus                 E: Ronda eliminatoria, F: Ronda final
     * @return pr                   Llista de Preguntes i respostes de la ronda
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    private List<PreguntaResposta> getPreguntesRespostesRonda(Integer idProva, String tipus) throws EOlympicsExceptionRonda, EOlympicsException{
        List<PreguntaResposta>pr=new ArrayList <PreguntaResposta>();
        Statement st=gestor.creaSentencia();
        String sql="SELECT numPregunta,opcioCorrecta "
                + "FROM RESPOSTACORRECTA "
                + "WHERE idProva="+idProva+" "
                + "AND tipusRonda='"+tipus+"' "
                + "ORDER BY numPregunta";
        try{
            ResultSet rs=st.executeQuery(sql);
            while (rs.next()){
                pr.add(new PreguntaResposta(rs.getInt(1),rs.getString(2)));
            }
        }catch (SQLException sqle){
           treatExceptionSQL(sqle.getMessage());
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
        }
        return pr;
    }
    /**
     * Accessor d'escriptura, guarda una ronda eliminatòria a la BBDD.
     * @param idProva                   idenficador de prova.
     * @param ronda                     Ronda Eliminatoria
     * @return Cert: si realitza l'escriptura, Fals: en cas contrari.
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    public boolean setAltaRondaEliminatoria(Integer idProva,RondaEliminatoria ronda) throws EOlympicsExceptionRonda, EOlympicsException{        
        return setAltaRonda(idProva,"E",ronda);
    }
   
    /**
     * Acessor d'escriptua, guarda una ronda Final a la BBDD
     * @param idProva               identificador de prova.
     * @param ronda                 Ronda Final
     * @return Cert: si realitza l'escriptura, Fals: en cas contrari.
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    public boolean setAltaRondaFinal(Integer idProva,RondaFinal ronda) throws EOlympicsExceptionRonda, EOlympicsException{        
        return setAltaRonda(idProva,"F",ronda);
    }
    
    
    
    public void setModificacioRondaEliminatoria(Integer idProva,RondaEliminatoria ronda) throws EOlympicsException, EOlympicsExceptionRonda{
        setModificacioRonda(idProva,"E",ronda);        
    }
    public void setModificacioRondaFinal(Integer idProva,RondaFinal ronda) throws EOlympicsException, EOlympicsExceptionRonda{
        setModificacioRonda(idProva,"F",ronda);        
    }
    
    
    /**
     * Accessor d'escriptura, guarda una ronda a la BBDD
     * @param idProva                   identificador de prova
     * @param tipus                     identificador de Ronda
     * @param ronda                     una Ronda
     * @return Cert: si realitza l'escriptura, Fals: en cas contrari.
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    private boolean setAltaRonda(Integer idProva,String tipus,Ronda ronda) throws EOlympicsExceptionRonda, EOlympicsException{
        boolean confirmat=false;
        Statement st=gestor.creaSentencia();        
        String sql="INSERT INTO RONDA "
                + "(idProva,tipusRonda,nombrePreguntes,dataIniciRealitzacio,dataFiRealitzacio) "
                + "VALUES(?,?,?,?,?)";
       try{
          
           PreparedStatement ps = gestor.crearPreparedStatement(sql);
           ps.setInt(1, idProva);
           ps.setString(2, tipus);
           ps.setInt(3, ronda.getNombrePreguntes());
           ps.setDate(4, new java.sql.Date(ronda.getDataIniRealitzacio().getTime())); 
           ps.setDate(5, new java.sql.Date(ronda.getDataFiRealitzacio().getTime())); 
           
           ps.execute();
           ps.close();                     
           setAltaRespostesRonda(idProva,tipus,ronda.getRespostesRonda());
           
           confirmat=true;
       }catch(SQLException sqle){
         
           treatExceptionSQL(sqle.getMessage());                            
       }catch (Exception e){
           
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
       }
        
        return confirmat;
    }
    
    /**
     * Acessor d'escriptura, guarda les preguntes i respostes d'una ronda.
     * @param idProva                   Identificador de prova
     * @param tipus                     Identificador de ronda
     * @param preguntes                 Llista de preguntes i respostes
     * @return n                        Numero de transaccions realitzades.
     * @throws EOlympicsExceptionRonda
     * @throws EOlympicsException 
     */
    private int setAltaRespostesRonda(Integer idProva, String tipus,List<PreguntaResposta> preguntes) throws EOlympicsExceptionRonda, EOlympicsException{
        String sql="INSERT INTO RESPOSTACORRECTA "
                + " (idProva,tipusRonda,numPregunta,opcioCorrecta) "
                + "VALUES(?,?,?,?)";        
        Integer n=0;
        try{
           PreparedStatement ps = gestor.crearPreparedStatement(sql);
           for(PreguntaResposta pr:preguntes){
                ps.setInt(1, idProva);
               
                ps.setString(2,tipus);
                
                
                ps.setInt(3,pr.getPregunta());
                ps.setString(4, pr.getResposta());
                if(ps.execute()) n++;
           }            
           ps.close();
           
       }catch(SQLException sqle){           
           treatExceptionSQL(sqle.getMessage());
                             
       }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
       }
        
        return n;
    }   
    private int setModificacioRespostesRonda(Integer idProva, String tipus,List<PreguntaResposta> preguntes) throws EOlympicsExceptionRonda, EOlympicsException{
        String sql="UPDATE RESPOSTACORRECTA "
                + " SET opcioCorrecta=? "
                + "WHERE idProva=? "
                + "AND tipusRonda=? "
                + "AND numPregunta=? ";
                
        Integer n=0;
        try{
           PreparedStatement ps = gestor.crearPreparedStatement(sql);
           for(PreguntaResposta pr:preguntes){
                ps.setString(1, pr.getResposta());               
                ps.setInt(2,idProva);                              
                ps.setString(3,tipus);
                ps.setInt(4, pr.getPregunta());
                if(ps.execute()) n++;
           }            
           ps.close();           
       }catch(SQLException sqle){           
           treatExceptionSQL(sqle.getMessage());                             
       }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
       }        
        return n;
    }
    private void setModificacioRonda(Integer idProva, String tipus,Ronda ronda ) throws EOlympicsException, EOlympicsExceptionRonda{
        Statement st=gestor.creaSentencia();
        String sql="UPDATE RONDA "
                + "SET nombrePreguntes=?,dataIniciRealitzacio=?,dataFiRealitzacio=? "
                + "WHERE idProva=? "
                + "AND tipusRonda=? ";
       PreparedStatement ps = gestor.crearPreparedStatement(sql);
       
       try{
           ps.setInt(1, ronda.getNombrePreguntes());           
           ps.setDate(2, new java.sql.Date(ronda.getDataIniRealitzacio().getTime()));
           ps.setDate(3, new java.sql.Date(ronda.getDataFiRealitzacio().getTime()));           
           ps.setInt(4, idProva);
           ps.setString(5, tipus);           
           ps.executeUpdate();
           ps.close();
           setModificacioRespostesRonda(idProva,tipus,ronda.getRespostesRonda());
       }catch(SQLException sqle){
            treatExceptionSQL(sqle.getMessage());
       }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
       }        
    }
    private boolean existeixRonda (Integer idProva,String tipus) throws EOlympicsException{
        boolean existeix=false;
        Statement st=gestor.creaSentencia();
        String sql="SELECT R.idProva "
                + "FROM RONDA R "                
                + "WHERE R.idProva="+ idProva 
                + " And R.tipusRonda='"+tipus+"'";
        try{
            ResultSet rs=st.executeQuery(sql);
            if (rs.next()){                              
                existeix=true;
            }
            st.close();
            rs.close();
        }catch (SQLException sqle){
            System.out.println(sqle.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_SQL);
        }catch (Exception e){
            System.out.println(e.getMessage());
            throw new EOlympicsException(EOlympicsException.ERR_DESC_EXEC);
        }
        
        return existeix;
    }
    private void treatExceptionSQL(String sqle) throws EOlympicsExceptionRonda, EOlympicsException{
           if(sqle.contains("pk_respostacorrecta")) {
               throw new EOlympicsExceptionRonda(EOlympicsExceptionRonda.ERR_SQL_PK_RONDA_PREGUNTA);
           }else if(sqle.contains("fk_ronda_rc")) {               
               throw new EOlympicsExceptionRonda(EOlympicsExceptionRonda.ERR_SQL_FK_RONDA_RC);
           }else if(sqle.contains("fk_usuari_alta_rc")) {               
               throw new EOlympicsExceptionRonda(EOlympicsExceptionRonda.ERR_SQL_FK_USUARI_RONDA);
           }else if(sqle.contains("pk_Ronda")) {
               throw new EOlympicsExceptionRonda(EOlympicsExceptionRonda.ERR_SQL_PK_RONDA);
           }else if(sqle.contains("fk_prova_rond")) {               
               throw new EOlympicsExceptionRonda(EOlympicsExceptionRonda.ERR_SQL_FK_PROVA_RONDA);
           }else if(sqle.contains("fk_usuari_alta_ronda")) {               
               throw new EOlympicsExceptionRonda(EOlympicsExceptionRonda.ERR_SQL_FK_USUARI_RONDA);
           }else if(sqle.contains("ck_datainsc")) {
               throw new EOlympicsExceptionRonda(EOlympicsExceptionRonda.ERR_SQL_CK_DATA_RONDA);
           }                              
           else{
               System.out.println(sqle);
               throw new EOlympicsException(EOlympicsException.ERR_SQL);
           }
        
    }
}
